<template>
  <formitem-wapper :formitem="formitem">
    <a-upload
      name="file"
      :multiple="true"
      :data="{ isup: 1 }"
      :headers="headers"
      v-decorator="[formitem.key, { valuePropName: 'fileList', getValueFromEvent: normFile, rules: formitem.rules }]"
      :beforeUpload="beforeUpload"
      :customRequest="customRequest"
      @change="handleChange"
      @download="handleDownload"
      @preview="handleDownload"
      v-bind="getAttrs()"
    >
      <a-button :disabled="btn_status"> <a-icon type="upload" />{{ text }} </a-button>
    </a-upload>
  </formitem-wapper>
</template>

<script>
import Vue from 'vue'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import { FormItemMixin } from './../FormItenMixin'
import FormitemWapper from './../FormitemWapper.vue'
import { removeArrayElement } from '@/utils/util.js'
import { apiUrl } from '@/api/api.js'
import { axios } from '@/utils/request'

const FILE_TYPE_ALL = 'all'
const FILE_TYPE_IMG = 'image'
const FILE_TYPE_TXT = 'file'
export default {
  name: 'UploadWidget',
  mixins: [FormItemMixin],
  components: {
    FormitemWapper
  },
  props: {
    text: {
      type: String,
      required: false,
      default: '点击上传'
    },
    bizPath: {
      type: String,
      required: false,
      default: 'temp'
    }
  },
  created() {
    // update--begin--autor:lvdandan-----date:20200925------for:扩展参数控制上传附件的单个还是多个
    if (this.formitem.formSchema.fieldExtendJson) {
      let json = JSON.parse(this.formitem.formSchema.fieldExtendJson)
      this.number = json.uploadnum ? json.uploadnum : 0
    }
    // update--begin--autor:lvdandan-----date:20200925------for:扩展参数控制上传附件的单个还是多个
    const token = Vue.ls.get(ACCESS_TOKEN)
    this.token = token
    this.headers = { 'X-Access-Token': token }
    if (this.widgetAttrs) {
      if (!this.widgetAttrs.disabled) {
        this.btn_status = false
      } else {
        this.btn_status = true
      }
    }
  },
  computed: {
    api() {
      return {
        objectPath: `/${this.uploadApiPath}/object-paths`,
        objectPrefix: `/${this.uploadApiPath}/object-prefix`,
        deleteObject: `/${this.uploadApiPath}/delete-object`
      }
    }
  },
  data() {
    return {
      uploadAction: apiUrl.fileUpload,
      headers: {},
      btn_status: false,
      fileType: FILE_TYPE_ALL,
      number: 0,
      token: '',
      fileMap: new Map(),
      uploadApiPath: 'property/upload-path', //上传业务接口前缀
      partSize: 1024 * 1024 * 50 //50M 文件
    }
  },
  methods: {
    beforeUpload(file) {
      var fileType = file.type
      if (fileType === FILE_TYPE_IMG) {
        if (fileType.indexOf('image') < 0) {
          this.$message.warning('请上传图片')
          return false
        }
      } else if (fileType === FILE_TYPE_TXT) {
        if (fileType.indexOf('image') >= 0) {
          this.$message.warning('请上传文件')
          return false
        }
      }
      // TODO 验证文件大小
      return true
    },
    customRequest(info) {
      this.fileMap.set(info.file.uid, {
        ...info,
        uploadIndex: 0,
        uploadId: undefined,
        etags: [],
        updated: function(newInfo) {
          info = { ...info.file, newInfo }
        }
      })
      this.getUploadInfo(info)
    },
    getUploadInfo(files) {
      const { file } = files
      //普通token 文件上传
      let params = {
        infos: [
          {
            fileName: file.name,
            objectSize: file.size,
            contextType: file.type,
            token: this.token
          }
        ]
      }
      axios({
        method: 'POST',
        url: this.api.objectPath,
        data: params
      })
        .then(res => {
          if (!res.success) {
            this.$message.warning(`上传失败,${res.message}`)
            this.$emit('uploadError', res.message || '获取上传信息失败')
            this.handleUploaded(file)
            return
          }

          let curFile = this.fileMap.get(file.uid)
          //给存档信息的参数
          curFile.postData = {
            ...res.result.infos[0],
            fileType: res.result.infos[0].contextType
          }
          curFile.uploadUrlSelf = res.result.infos[0].url
          curFile.etags = []
          this.initChunking(file)
        })
        .catch(err => {
          this.$message.warning(`上传失败,${err.response.data.message}`)
          this.handleUploaded(file)
        })
    },
    initChunking(file) {
      let params = {
        acl: 1,
        uploads: ''
      }
      if (this.uploadType == 1) {
        params.token = this.token
      }
      axios({
        method: 'POST',
        url: this.fileMap.get(file.uid).uploadUrlSelf,
        params
      })
        .then(res => {
          if (!res.success) {
            this.$message.warning(`上传失败,${res.message}`)
            this.$emit('uploadError', res.message || '上传文件失败')
            this.handleUploaded(file)
            return
          }
          this.fileMap.get(file.uid).uploadId = res.result.uploadId
          this.fileMap.get(file.uid).chunkNum = Math.ceil(file.size / this.partSize)
          this.uploadFirstPart(file)
        })
        .catch(() => {
          this.$emit('uploadError', '上传文件失败')
          this.handleUploaded(file)
        })
    },
    /**
     * 上传第一块文件内容
     */
    uploadFirstPart(file) {
      let chunk = file.slice(0, this.partSize)
      if (this.fileMap.get(file.uid).chunkNum === 1) {
        chunk = file
      }
      const formData = new FormData()
      formData.append('file', chunk)
      let params = {
        offset: 0,
        partNumber: 1,
        partSize: this.fileMap.get(file.uid).chunkNum === 1 ? file.size : this.partSize,
        uploadId: this.fileMap.get(file.uid).uploadId
      }
      if (this.uploadType == 1) {
        params.token = this.token
      }
      axios({
        method: 'PUT',
        url: this.fileMap.get(file.uid).uploadUrlSelf,
        Headers: {
          'Content-Type': 'multipart/form-data'
        },
        params: params,
        data: formData
      })
        .then(res => {
          if (res.success) {
            this.fileMap.get(file.uid).etags.push(res.result.etag)
            if (1 === this.fileMap.get(file.uid).chunkNum) {
              this.mergeUploadFile(file)
            } else {
              this.uploadPartAll(file)
            }
          } else {
            this.$message.warning(`上传失败`)
            this.$emit('uploadError', res.message || '上传文件失败')
            this.handleUploaded(file)
          }
        })
        .catch(() => {
          this.$message.warning(`上传失败`)
          this.$emit('uploadError', '上传文件失败')
          this.handleUploaded(file)
        })
    },
    /**
     * 并发分块上传剩余所有分块(除第一块外)
     */
    uploadPartAll(file) {
      let list = []
      for (let i = 2; i <= this.fileMap.get(file.uid).chunkNum; i++) {
        list.push(this.uploadPart(i, file, this.partSize * (i - 1), this.partSize * i))
      }
      Promise.all(list)
        .then(ress => {
          if (ress instanceof Array && ress.length && ress.every(res => res.success)) {
            this.mergeUploadFile(file)
          } else {
            this.$message.warning(`上传失败`)
            this.$emit('uploadError', '上传分块文件失败')
            this.handleUploaded(file)
          }
        })
        .catch(() => {
          this.$message.warning(`上传失败`)
          this.$emit('uploadError', '上传分块文件失败')
          this.handleUploaded(file)
        })
    },
    /**
     * 分块上传
     * @param {*} n 块数
     * @param {*} file 文件
     * @param {*} start 分块开始
     * @param {*} end 分块结束
     */
    uploadPart(n, file, start, end) {
      let chunk = file.slice(start, end)
      if (n === this.fileMap.get(file.uid).chunkNum && end > file.size) {
        chunk = file.slice(start)
      }
      const formData = new FormData()
      formData.append('file', chunk)
      const partSize = end > file.size ? file.size - start : end - start
      let params = {
        offset: (n - 1) * this.partSize,
        partNumber: n,
        partSize,
        uploadId: this.fileMap.get(file.uid).uploadId,
        token: this.token
      }
      return axios({
        method: 'PUT',
        url: this.fileMap.get(file.uid).uploadUrlSelf,
        Headers: {
          'Content-Type': 'multipart/form-data'
        },
        params,
        data: formData
      }).then(res => {
        if (res.success) {
          this.fileMap.get(file.uid).etags[n - 1] = res.result.etag

          return Promise.resolve(res)
        } else {
          return Promise.reject(res)
        }
      })
    },
    /**
     * 合并上传文件
     */
    mergeUploadFile(file) {
      let params = {
        uploadId: this.fileMap.get(file.uid).uploadId,
        token: this.token
      }
      axios({
        method: 'POST',
        url: this.fileMap.get(file.uid).uploadUrlSelf,
        params,
        data: this.fileMap.get(file.uid).etags
      })
        .then(res => {
          if (!res.success) {
            this.$message.warning(`上传失败,${res.message}`)
            this.$emit('uploadError', res.message || '上传分块文件失败')
            this.handleUploaded(file)
            return
          }
          const tempData = Object.assign(res.result, this.fileMap.get(file.uid).postData)
          const params = {
            realPath: tempData.url,
            url: tempData.url,
            providerUrl: tempData.providerUrl,
            fileSize: tempData.objectSize,
            fileSuffix: tempData.fileSuffix,
            fileType: tempData.fileType,
            fileName: file.name,
            storageLocation: 1,
            uid: file.uid,
            thumbUrl: tempData.url
          }
          this.fileMap.get(file.uid).updated(params)
          this.fileMap.get(file.uid).onSuccess(params, this.fileMap.get(file.uid))
          this.handleUploaded(file, true)
        })
        .catch(() => {
          this.$emit('uploadError', '上传分块文件失败')
          this.handleUploaded(file, false)
        })
    },
    // 上传文件结束清空数据
    handleUploaded(file, success) {
      try {
        this.fileMap.get(file.uid).files = []
        this.fileMap.get(file.uid).uploadIndex = 0
        if (success) {
          this.fileMap.get(file.uid).resolve({ url: this.fileMap.get(file.uid).postData.url })
        } else {
          this.fileMap.get(file.uid).reject({ url: undefined, status: 'reject', message: '' })
        }
        this.fileMap.get(file.uid).postData = {}
      } catch (e) {}
      this.isLoading = false
    },
    handleChange(info) {
      // update--begin--autor:lvdandan-----date:20200925------for:扩展参数控制上传附件的单个还是多个
      // number大于0时限制上传个数
      if (this.number > 0) {
        info.fileList = info.fileList.slice(-this.number)
      }
      // update--begin--autor:lvdandan-----date:20200925------for:扩展参数控制上传附件的单个还是多个
      console.log('文件列表改变')
      if (info.file.status !== 'uploading') {
        console.log(info.file, info.fileList)
      }
      if (info.file.status === 'done') {
        // let url = info.file.response.message
        // this.$message.success(`${info.file.name} file uploaded successfully`);
        // update-begin-autor:taoyan date:20201130 for:文件上传失败从列表中移除
        if (info.file.response.success == false) {
          this.$message.error(info.file.response.message)
          removeArrayElement(info.fileList, 'uid', info.file['uid'])
        }
        info.fileList = info.fileList.map(file => {
          if (file.response) {
            file.status = 'done'
            file.url = file.response.url
            file.thumbUrl = file.response.thumbUrl + '?token=' + this.token
          }
          return file
        })
        // update-end-autor:taoyan date:20201130 for:文件上传失败从列表中移除
      } else if (info.file.status === 'error') {
        this.$message.error(`${info.file.name} file upload failed.`)
      } else if (info.file.status === 'removed') {
        this.handleDelete(info.file)
      }
    },
    handleDelete(file) {
      // 如有需要新增 删除逻辑
      console.log(file)
    },
    normFile(e) {
      if (Array.isArray(e)) {
        return e
      }
      return e && e.fileList
    },
    handleDownload(file) {
      if (
        file.url.endsWith('.jpg') ||
        file.url.endsWith('.png') ||
        file.url.endsWith('.jpeg') ||
        file.url.endsWith('.gif')
      ) {
        window.open(file.thumbUrl, 'top')
        return
      }
      //    const imgWindow = window.open('')
      // imgWindow && imgWindow.document.write(`<image src='${file.thumbUrl}' style='display: flex; margin: 0 auto'/>`)
      let url = file.thumbUrl + '&need-download=1'
      //获得id为downLoadListFrame的frame
      var divFrame = window.parent.document.getElementById('downLoadListFrame')
      //判断是否存在，如果存在先移除，再重新创建
      if (divFrame != null) {
        window.parent.document.body.removeChild(divFrame)
      }
      var iframe = document.createElement('iframe')
      iframe.setAttribute('id', 'downLoadListFrame')
      iframe.src = url
      document.body.appendChild(iframe)
      // 不加下面语句会自动下载2次---不是很理解
      setTimeout(function() {
        iframe.src = ''
      }, 1000)
    },
    getAttrs() {
      let curWidgetAttr = this.widgetAttrs
      let viewType = this.formitem.type
      if (FILE_TYPE_IMG == viewType) {
        this.fileType = FILE_TYPE_IMG
        return {
          listType: 'picture',
          ...curWidgetAttr
        }
      } else {
        return curWidgetAttr
      }
    }
  }
}
</script>

<style scoped></style>
